/*
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

/*
 *
 *
 *
 *
 *
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

package java.util.concurrent.locks;

import java.util.concurrent.TimeUnit;
import java.util.Collection;

/**
 * 互斥锁 或 排他锁 或 重入锁

 * 除了实现Lock接口外，这个类还定义了许多公共和受保护的方法来检查锁的状态。
 * 其中一些方法仅适用于仪器和监测。
 * 此类的序列化行为与内置锁相同：反序列化的锁处于未锁定状态，而与序列化时的状态无关。
 * 此锁最多支持同一线程的2147483647个递归锁。试图超过此限制会导致锁定方法的错误抛出。

 * 1、支持重入
 * 2、支持超时
 * 3、支持公平和非公平
 * 4、支持可中断
 * 5、支持多条件
 */


public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;

    private final Sync sync;

    /**
     * 空参构造,sync默认是非公平锁
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * 有参构造(默认非公平锁)
     * {@code true}  公平锁
     * {@code false} 非公平锁
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }




    // sync队列，公平锁和非公平锁

    /**
     * 此锁的同步控制的基础
     * 1、公平锁
     * 2、非公平锁
     * 使用AQS状态表示锁上的保持次数(可重入性)
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * 加锁方法
         */
        abstract void lock();

        /**
         * 非公平锁加锁
         * 1、如何理解插队, 这里的插队是当前队列中被唤醒的线程, 和当前加入的线程都可以被执行
         * 2、如果当前加入线程比队列中唤醒的线程先获取到锁, 就是插队现象
         */
        final boolean nonfairTryAcquire(int acquires) {
            // 获取当前线程
            final Thread current = Thread.currentThread();
            // 获取AQS的state的值
            int c = getState();

            // 如果state状态为0, 尝试再次获取锁资源
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            } else if (current == getExclusiveOwnerThread()) {
                // 当前线程持有锁, state 计数 +1. 重入锁操作
                int nextc = c + acquires;
                // 如果+1后,小于0,超锁可重入的最大值,抛出error
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                // 没问题,就重新对state进行复制
                setState(nextc);
                return true;
            }
            // 返回false状态,tryAcquire失败的几种情况
            // 1、锁被其他线程持有
            // 2、没有任何线程持有锁的情况下,此时多线程并发通过CAS修改state(只能被一个线程成功修改),其他线程未获取到锁
            return false;
        }

        /**
         * 公平锁和非公平锁，尝试释放锁
         * 此方法用于在独占模式下释放锁它减去当前状态值与提供的释放值如果当前线程不是锁的持有者，
         * 则抛出IllegalMonitorStateException如果释放后状态值为0，则表示锁已经完全释放，并设置独占所有者线程为null
         * @param releases 要减去当前状态的值
         * @return 如果锁在此次释放后完全释放（即状态值为0），则返回true；否则返回false
         * @throws IllegalMonitorStateException 如果当前线程不是锁的持有者
         */
        protected final boolean tryRelease(int releases) {
            // 计算释放后的新状态值
            int c = getState() - releases;
            // 检查当前线程是否是锁的持有者，如果不是，则抛出异常
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            // 初始化是否完全释放的标志为false
            boolean free = false;
            // 如果释放后状态值为0，则表示锁已经完全释放
            if (c == 0) {
                // 设置完全释放标志为true
                free = true;
                // 将独占所有者线程设置为null，表示锁已经完全释放
                setExclusiveOwnerThread(null);
            }
            // 更新当前状态值
            setState(c);
            // 返回锁是否已经完全释放的标志
            return free;
        }
        /**
         * 判断当前锁是否被当前线程独占性地持有
         * 此方法用于确定锁的状态，以决定是否允许当前线程进行某些操作（例如释放锁或重复获取锁）
         * @return 如果锁被当前线程独占性地持有，则返回true；否则返回false
         */
        protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();   // 比较当前锁的独占所有者线程与当前正在执行的线程是否相同
        }

        /**
         * 获取当前线程持有锁的次数
         * 此方法用于在同步代码块或方法中确定当前线程是否独占持有锁如果是，
         * 则返回持锁的次数；如果不是，则返回0这在分析同步代码的复杂逻辑中很有用，
         * 特别是在处理多线程和可重入锁的情况下
         * @return 如果当前线程独占持有锁，则返回持锁次数；否则返回0
         */
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        /**
         * 创建并返回一个新的ConditionObject实例
         * 此方法用于生成与当前锁绑定的新条件变量对象，用于协调线程间的协作
         * @return 新的ConditionObject实例
         */
        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        /**
         * 获取当前锁的拥有者线程
         * 此方法用于判断锁的状态，并根据状态返回相应的线程信息
         * 如果锁是可用状态（即未被任何线程拥有），则返回null
         * 如果锁已被独占，则返回独占此锁的线程
         * @return 如果锁是可用的，则返回null；否则返回独占此锁的线程
         */
        final Thread getOwner() {
            // 检查锁的状态，如果状态为0，表示锁是可用的，返回null
            // 否则，表示锁已被独占，返回独占此锁的线程
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        /**
         * 判断当前对象是否处于锁定状态
         * @return 如果当前对象的内部状态不为0，则表示对象处于锁定状态，返回true；否则，返回false
         */
        final boolean isLocked() {
            return getState() != 0;
        }


        /**
         * 自定义对象反序列化方法
         * 该方法在对象被反序列化时调用，用于执行自定义的反序列化过程
         * 主要目的是在对象反序列化后重置对象的状态
         * @param s 对象输入流，用于读取序列化对象的数据
         * @throws java.io.IOException 如果读取过程中发生I/O错误
         * @throws ClassNotFoundException 如果无法找到对应类
         */
        private void readObject(java.io.ObjectInputStream s)
                throws java.io.IOException, ClassNotFoundException {
            // 调用默认的反序列化方法，恢复对象的默认状态
            s.defaultReadObject();
            // 在反序列化完成后，将对象的状态设置为初始状态（0）
            setState(0);
        }
    }

    /**
     * 非公平锁
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        final void lock() {
            // 直接尝试加锁
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                // 如果获取锁失败进入 AQS acquire逻辑
                acquire(1);
        }

        /**
         * 尝试获取锁,直接调用到 nonfairTryAcquire非公平锁的加锁逻辑 里面有两个逻辑
         * 1、如果当前状态无锁,直接尝试加锁,加锁成功后返回true
         * 2、如果当时锁重入,那么直接修改AQS状态共享变量值state==c+acquires,加锁返回true
         * 3、如果都不满足,那么返回加锁失败返回false
         */
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

    /**
     * 公平锁
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
        final void lock() {
            acquire(1);
        }
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                        compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            } else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                //解释 nextc < 0 报超过锁数量最大值的原因？
                //在大多数情况下，c 和 acquires 都是非负整数。如果 c 已经非常接近 int 类型的最大值（2147483647），再增加 acquires 可能会导致 nextc 超过 int 的最大值，从而发生溢出，变成一个负数
                //发生溢出后，nextc 变成负数，这在逻辑上是不合理的，因为锁的数量不可能是负数。因此，这里抛出 Error 异常，提示“最大锁数量已超过”
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }




    //  获取锁

    /**
     * 获取锁
     * 1、如果锁没有被另一个线程持有，则获取锁，并立即返回，将锁持有计数设置为1。
     * 2、如果当前线程已经持有锁，那么持有计数将增加1，并且该方法立即返回。
     * 3、如果锁由另一个线程持有，则当前线程出于线程调度目的而被禁用，并且处于休眠状态，直到获取了锁为止，此时锁持有计数被设置为1。 3
     */
    public void lock() {
        sync.lock();
    }

    /**
     * 尝试获取锁
     */
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

    /**
     * 尝试获取锁,支持设置获取锁的超时时间
     */
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

    /**
     * 获取锁后允许可中断
     */
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }


    // 解锁

    /**
     * 解锁，释放当前锁的状态,在 AQS 队列中去唤醒排队的头节点
     */
    public void unlock() {
        sync.release(1);
    }

    /**
     * 创建条件等待队列
     */
    public Condition newCondition() {
        return sync.newCondition();
    }

    /**
     * 获取当前线程持有锁的次数
     */
    public int getHoldCount() {
        return sync.getHoldCount();
    }

    /**
     * 判断当前线程是否持有独占锁
     */
    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }
    /**
     * 判断对象是否处于锁定状态
     */
    public boolean isLocked() {
        return sync.isLocked();
    }

    /**
     * 判断该锁是否为公平锁
     */
    public final boolean isFair() {
        return sync instanceof FairSync;
    }

    /**
     * 获取当前同步资源的持有者线程
     * 此方法用于返回当前同步资源（如锁）的持有者线程对象
     * 它通过调用sync对象的getOwner方法来实现，sync对象是一个同步机制实例
     * @return Thread 当前同步资源的持有者线程，如果没有线程持有，则返回null
     */
    protected Thread getOwner() {
        return sync.getOwner();
    }

    /**
     * 最终方法，检查是否有线程已经排队等待执行
     * 此方法用于判断当前条件下，是否有线程在等待队列中
     * 主要用于调试和监控，以了解线程的排队情况
     * @return 如果有线程已经排队等待执行，则返回true；否则返回false
     */
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    /**
     * 判断指定的线程是否已经排队等待锁
     */
    public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }

    /**
     * 获取队列长度
     */
    public final int getQueueLength() {
        return sync.getQueueLength();
    }

    /**
     * 获取当前正在排队等待的线程集合
     */
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

    /**
     * 检查指定的Condition是否有等待的线程
     * @param condition 要检查的Condition对象，不能为空
     * @return 如果指定的Condition有等待的线程，则返回true；否则返回false
     * @throws NullPointerException 如果condition为null
     * @throws IllegalArgumentException 如果condition不是由当前同步器创建的ConditionObject实例
     */
    public boolean hasWaiters(Condition condition) {
        // 检查condition是否为null，如果是，则抛出NullPointerException
        if (condition == null)
            throw new NullPointerException();
        // 检查condition是否是由当前同步器创建的ConditionObject实例，如果不是，则抛出IllegalArgumentException
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        // 调用同步器的hasWaiters方法，检查指定Condition是否有等待的线程
        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject) condition);
    }

    /**
     * 获取等待队列的长度
     * 此方法用于获取特定Condition条件关联的等待队列的长度
     * 它首先检查给定的Condition对象是否为null，如果是，则抛出NullPointerException
     * 然后，它验证该Condition对象是否属于AbstractQueuedSynchronizer.ConditionObject类型
     * 如果不是，则抛出IllegalArgumentException，表明该Condition对象非法
     * 最后，它调用同步器的getWaitQueueLength方法，传入验证过的Condition对象，以获取等待队列的长度
     * @param condition 要查询的Condition对象，不能为null
     * @return 返回指定Condition条件关联的等待队列的长度
     * @throws NullPointerException 如果给定的Condition对象为null
     * @throws IllegalArgumentException 如果给定的Condition对象不属于正确的类型
     */
    public int getWaitQueueLength(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject) condition);
    }

    /**
     * 获取等待在特定条件下的线程集合
     * @param condition 条件变量，用于控制线程的等待和唤醒
     * @return Collection<Thread> 返回等待在该条件上的线程集合
     * @throws NullPointerException 如果提供的条件变量为null，则抛出此异常
     * @throws IllegalArgumentException 如果提供的条件变量不属于当前同步器，则抛出此异常
     */
    protected Collection<Thread> getWaitingThreads(Condition condition) {
        // 检查条件变量是否为null，如果是，则抛出NullPointerException
        if (condition == null)
            throw new NullPointerException();
        // 检查条件变量是否属于当前同步器，如果不是，则抛出IllegalArgumentException
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        // 调用同步器的getWaitingThreads方法，获取等待在指定条件上的线程集合
        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject) condition);
    }

    public String toString() {
        Thread o = sync.getOwner();
        return super.toString() + ((o == null) ?
                "[Unlocked]" :
                "[Locked by thread " + o.getName() + "]");
    }
}
